<?php

namespace app\company\controller;

use app\common\controller\CompanyController;
use app\common\enum\order\AllowStatus;
use app\common\enum\order\OrderStatus;
use app\common\enum\order\OrderType;
use app\common\enum\order\PayType;
use app\common\exception\BaseException;
use app\common\Jobs\ReportDriverDeliveryJob;
use app\common\model\CompanyWarehouse;
use app\common\model\DealerGoods as DealerGoodsModel;
use app\common\model\DealerGoodsSpec;
use app\common\model\DeliveryLog;
use app\common\model\ReceiveLog;
use app\common\model\RegionStore;
use app\common\service\annotation\ControllerAnnotation;
use app\common\service\annotation\NodeAnnotation;
use app\company\model\CompanyOrder;
use app\company\model\CompanyOrderDetail;
use app\company\model\Delivery as DeliveryModel;
use app\company\model\DeliveryOrder;
use app\mini\model\ChangeCompanyOrderLog;
use app\Request;
use think\App;
use think\db\exception\DbException;
use think\facade\Queue;
use think\response\Json;

/**
 * @ControllerAnnotation(title="配送单")
 */
class Delivery extends CompanyController
{
    public function __construct(App $app)
    {
        parent::__construct($app);
        $this->model = new CompanyOrder();
        $this->sort = ['create_time' => 'desc'];
        $this->each  = true;
    }

    /**
     * @NodeAnnotation(title="订单列表")
     * 物流单指订单中销售属性单订单
     * @throws DbException
     */
    public function list(): Json
    {
        $op = $this->request->get('op');
        $op = $op ? json_decode($op, true) : null;
        list($limit, $where) = $this->buildSearchParams();

        // 获取列表数据
        $query = $this->getBaseQuery($where);
        $type = $this->request->get('type');
        $list = $type ? $query->select() : $query->paginate($limit);

        if ($this->each) {
            $list = $this->each($list);
        }
        $list = $list->toArray();

        // 统计数据
        $statistics = $this->getStatistics($where);

        // 如果是选定数据，就需要返回统计数据
        $data = [];
        if (isset($op['id'])) {
            $statistics = array_merge($statistics, $this->calculateListStatistics($list));
        }

        if ($type) {
            $data = array_merge([
                'items' => $list
            ], $statistics);
        } else {
            $list = array_merge($list, $statistics);
        }

        return $this->success($data ?: $list);
    }

    /**
     * 根据条件进行预加载获取数据
     * @param $where
     * @return CompanyOrder
     */
    protected function getBaseQuery($where)
    {
        return $this->model
            ->where($this->defaultWhere)
            ->where($where)
            ->where('order_type', 'in', [OrderType::SALES, OrderType::RETURN])
            ->where('order_status', '<>', OrderStatus::CANCEL)
            ->where('check_status', '=', 2)
            ->where('is_self_order', 1)
            ->where('is_cx', 1)
            ->order($this->sort)
            ->with([
                'store' => function ($query) {
                    $query->with('region');
                },
                'dealer' => function ($query) {
                    $query->field('id,name');
                },
                'salesman' => function ($query) {
                    $query->field('id,rename');
                },
                'driver' => function ($query) {
                    $query->field('id,name');
                },
                'assistDriver' => function ($query) {
                    $query->field('id,name');
                },
                'detail' => function ($query) {
                    $query->with([
                        'goods' => function ($query) {
                            $query->withTrashed()->field('id,image,name');
                        },
                        'goodsSpec' => function ($query) {
                            $query->withTrashed()->field('id,image,name,weight,length,width,height,driver_money,unit,unit_convert');
                        }
                    ]);
                },
                'deliveryLog' => function ($query) {
                    $query->where('company_order_id', 'exp', '= id');
                },
                'receiveLog' => function ($query) {
                    $query->where('payee_type', 2);
                },
                'changeCompanyOrder' => function ($query) {
                    $query->where('company_id', $this->companyId)->field('id,company_order_pid,company_order_id');
                }
            ]);
    }

    /**
     * 计算司机收益
     * @param $where
     * @return array
     */
    protected function getStatistics($where)
    {
        $query = $this->getBaseQuery($where)->where('order_type', OrderType::SALES);
        $driver_money = $query->value('SUM(driver_money)');
        $assist_driver_money = $query->value('SUM(assist_driver_money)');

        return [
            'driver_money' => $driver_money,
            'assist_driver_money' => $assist_driver_money
        ];
    }

    /**
     * 全量统计
     * @param $list
     * @return array
     */
    protected function calculateListStatistics(array $list): array
    {
        // 初始化正常订单的统计信息
        $normalStats = $this->calculateStats($list, function ($item) {
            return $item['order_amount'] > 0;
        });

        // 初始化退货订单的统计信息
        $returnedStats = $this->calculateStats($list, function ($item) {
            return $item['order_amount'] < 0;
        });

        // 返回合并后的统计信息
        return array_merge(
            $this->formatStats($normalStats, 'count_total'),
            $this->formatStats($returnedStats, 'returned_count_total')
        );
    }

    // 计算统计信息的辅助函数
    private function calculateStats(array $list, callable $condition): array
    {
        $totalWidth = 0;
        $totalVolume = 0;
        $totalMoney = 0;
        $totalNumber = 0;

        foreach ($list as $item) {
            if ($condition($item)) {
                $totalWidth += $item['totalWidth'];
                $totalVolume += $item['totalVolume'];
                $totalMoney += $item['totalMoney'];
                $totalNumber += $item['order_amount'];
            }
        }

        return [
            'width' => $totalWidth,
            'volume' => $totalVolume,
            'money' => $totalMoney,
            'number' => $totalNumber
        ];
    }

    // 格式化统计信息的辅助函数
    private function formatStats(array $stats, string $prefix): array
    {
        $formattedStats = [];
        foreach ($stats as $key => $value) {
            $formattedStats[$prefix . '_' . $key] = $value;
        }
        return $formattedStats;
    }

    /**
     * 数据结构转换
     * @param $list
     * @return mixed
     */
    public function each($list)
    {
        return $list->each(function (&$vo) {
            // 初始化合计数据
            $totalVolume = 0;
            $totalWidth = 0;
            $totalNumber = 0;
            $totalMoney = 0;

            // 处理门店信息
            if (isset($vo->store)) {
                $vo->store->region = $vo->store->region ?? '';
            } else {
                $vo->store = [];
            }

            // 处理经销商信息
            $vo->dealer = $vo->dealer ?? [];

            // 处理业务员信息
            $vo->salesman = $vo->salesman ?? [];

            // 处理司机信息
            $vo->driver = $vo->driver ?? [];

            // 处理副驾司机信息
            $vo->assist_driver = $vo->assistDriver ?? [];

            // 处理订单详情
            $vo->detail = $vo->detail ?? [];
            foreach ($vo->detail as &$item) {
                // 商品信息
                $item->goods = $item->goods ?? [];

                // 商品规格信息
                $item->goodsSpec = $item->goodsSpec ?? [];

                // 计算体积
                if (!empty($item->goodsSpec)) {
                    $item->goods->volume = $item->goodsSpec->length * $item->goodsSpec->width * $item->goodsSpec->height;
                    $totalVolume += $item->goods->volume * $item->num;
                    $totalWidth += $item->goodsSpec->width * $item->num;
                    $totalNumber += $item->num;
                    $totalMoney += $item->total_price;
                }
            }

            $vo->totalVolume = $totalVolume;// 订单体积统计
            $vo->totalWidth = $totalWidth;// 订单重量统计
            $vo->totalNumber = $totalNumber;// 订单数量统计
            $vo->totalMoney = $totalMoney;// 订单金额统计

            $vo->delivery_log = $vo->delivery_log ?? null;
            if ($vo->delivery_log && !empty($vo->delivery_log->image)) {
                $vo->delivery_log->image = explode(',', $vo->delivery_log->image);
            }

            $vo->receive_log = $vo->receive_log ?? null;
            if ($vo->receive_log) {
                $vo->receive_log->pay_type_text = PayType::getPayTypeText($vo->receive_log->pay_type);
            }

            $vo->is_change = $vo->changeCompanyOrder ? 1 : 2; // 1: 没有修改过, 2: 修改过
            $vo->is_change_text = $vo->changeCompanyOrder ? '未修改' : '修改过';
            unset($vo->changeCompanyOrder);

            return $vo;
        });
    }

    /**
     * @NodeAnnotation(title="门店配送任务")
     *  地图圈存门店单销售订单，地址只显示为生成配送单的数据
     */
    public function store(): Json
    {
        $get   = $this->request->get();
        $where = [
                ['pid', '<>', 0],
                ['order_status', '=', OrderStatus::BEING],
                ['check_status', '=', 2],
                ['allow_status', '=', 1],
                ['order_type', '=', OrderType::SALES],
                ['driver_id', '=', 0],
                ['company_id', '=', $this->companyId],
                ['is_cx', '=', 1],
                ['is_self_order', '=', 1]
        ];
        if (!empty($get['id'])) {
            $where[] = ['id', 'in', explode(',', $get['id'])];
        }
        // 获取订单列表
        $this->model->where($where)->group('store_id')->select()->each(function ($item) use (&$list, $where)
        {
            // 获取该门店订单ids
            $where[]  = ['store_id', 'in', $item->store_id];
            $orderIds = $this->model->where($where)->column('id');
            $list[]   = [
                    'store_id'  => $item->store_id,
                    'lng'       => $item->store()->value('lon'),
                    'lat'       => $item->store()->value('lat'),
                    'store'     => $item->store()->value('name'),
                    'orderIds'  => implode(',', $orderIds),
                    'order_num' => count($orderIds),
                    'weight'    => 0,
                    'volume'    => 0
            ];
        });
        $local = (new CompanyWarehouse())->local($this->companyId);
        if (!$local) return $this->error('获取仓库位置失败，请联系管理员');
        $center = [
                'lng' => $local->lon,
                'lat' => $local->lat
        ];
        return $this->success(compact('list', 'center'));
    }

    /**
     * @NodeAnnotation(title="分配配送员")
     * 分配任务给司机
     */
    public function assign(Request $request): Json
    {
        try {
            $this->checkPost();
            $info = $request->param('info', '');
            if (!$info) return $this->error('数据不能空');
            //            if ($info->allow_status != AllowStatus::WAIT) return $this->error('订单状态不正确');
            $info = json_decode($info, true);
            $this->model->transaction(function () use ($info)
            {
                array_walk($info, function ($item)
                {
                    if (!$item['driver_id']) throw new BaseException('配送员不能为空');
                    if (!$item['store_id']) throw new BaseException('门店不能为空');
                    $where    = [
                            ['pid', '<>', 0],
                            ['order_status', '=', OrderStatus::BEING],
                            ['order_type', '=', OrderType::SALES],
                            ['allow_status', '=', AllowStatus::WAIT],
                            ['driver_id', '=', 0],
                            ['store_id', 'in', explode(',', $item['store_id'])],
                            ['is_cx', '=', 1],
                            ['is_self_order', '=', 1]
                    ];
                    $orderIds = $this->model->where($where)->column('id');
                    $this->model->where($where)
                                ->save(['driver_id' => $item['driver_id'], 'allow_status' => AllowStatus::ALREADY]);
                    $this->createDelivery($orderIds, $item['driver_id'], $item['assist_driver_id']);
                });
            });
        } catch (\Exception $e) {
            return $this->error("生成失败:" . $e->getMessage());
        }
        return $this->success('生成成功');
    }

    /**
     * @NodeAnnotation(title="分配任务")
     */
    public function assignCommit(Request $request, $id = 0): Json
    {
        try {
            $this->checkPost();
            $post = $request->post();
            $post['type'] = $request->post('type',0);
            $rule = [
                    'id|订单'                 => 'require',
                    'driver_id|配送员'        => 'require',
            ];
            $post['assist_driver_id'] = $request->post('assist_driver_id', 0);
            $this->validate($post, $rule);
            $id                         = explode(',', $id);
            $this->model->transaction(function () use ($id,$post)
            {
                $company_order_detail_model = new CompanyOrderDetail();
                // 更新订单详情司机协送人
                $update_data = ['driver_id' => $post['driver_id'], 'assist_driver_id' => $post['assist_driver_id']];
                $company_order_detail_model->where('company_order_id', 'in', $id)->save($update_data);
                // 更新订单信息
                $update_data['allow_status'] = AllowStatus::ALREADY;
                if($post['type'] == 1){
                    $update_data['delivery_status'] = 1;
                }elseif ($post['type'] == 2){
                    $update_data['delivery_status'] = 2;
                }elseif ($post['type'] == 3){
                    $update_data['delivery_status'] = 4;
                }
                $this->model->where('id', 'in', $id)->save($update_data);

                $orderIds    = $this->model->where('id', 'in', $id)->column('id');
                $this->createDelivery($orderIds,$post['driver_id'], $post['assist_driver_id'],$post['type']);
            });
        } catch (\Exception $e) {
            return $this->error('生成失败:' . $e->getMessage());
        }
        return $this->success('生成成功');
    }

    /**
     * 生成配送单
     */
    private function createDelivery($orderIds, $driverId, $assist_driver_id,$type=0): void
    {
        // 判定参数是否合理
        if (empty($orderIds) || empty($driverId)) return;
        // 如果有就绑定，没有就新增
        $data          = [];
        $storeNum      = (new CompanyOrder())->field('store_id')->where('id', 'in', $orderIds)
                                                                ->group('store_id')
                                                                ->count();
        $goodsNum      = (new CompanyOrderDetail())->where('company_order_id', 'in', $orderIds)->sum('num');
        $deliveryData  = [
                'delivery_no'       => generateOrderNo('PS'),
                'store_num'         => $storeNum,
                'order_num'         => count($orderIds),
                'goods_num'         => $goodsNum,
                'company_id'        => $this->companyId,
                'driver_id'         => $driverId,
                'assist_driver_id'  => $assist_driver_id,
                'company_order_ids' => implode(',', $orderIds),
                'status' => empty($type) ? 4 :$type,
        ];
        $delivery_status = 1;
        if ($type == 3) $delivery_status = 2;
        $deliveryModel = new DeliveryModel();
        $deliveryModel->save($deliveryData);
        foreach ($orderIds as $orderId) {
            $data[] = [
                    'delivery_id'      => $deliveryModel->id,
                    'company_order_id' => $orderId,
                    'delivery_status'  => $delivery_status,
            ];
        }
        (new DeliveryOrder())->saveAll($data);
        // 异步统计
        $info = [
                'driver_id'        => $driverId,
                'assist_driver_id' => $assist_driver_id,
                'company_id'       => $this->companyId,
                'store_num'        => $storeNum,
                'order_num'        => count($orderIds),
        ];
        // 确认出库减商品库存
        if($type == 3){
            (new CompanyOrderDetail())->where('company_order_id', 'in', $orderIds)->select()->each(function ($vo){
                $spec = (new DealerGoodsSpec())->find($vo->dealer_goods_spec_id);
                (new DealerGoodsModel())->where('id',$vo->dealer_goods_id)
                                        ->dec('sales_stock', $vo['num'] * $spec->ratio)
                                        ->save();
            });
        }
        if($type != 1) Queue::push(ReportDriverDeliveryJob::class, $info, 'report_driver_delivery');
    }
}
